#include "stdafx.h"
#include "..\headers\InputSystem.h"

namespace ne{

InputSystem::InputSystem(void) : 
	m_oisInputManager(nullptr), 
	m_keyboard(nullptr), 
	m_mouse(nullptr), 
	m_renderWindow(nullptr) {}
InputSystem::~InputSystem(void){}

void InputSystem::_Init(Ogre::RenderWindow* renderWindow){
	m_renderWindow = renderWindow;
	Ogre::WindowEventUtilities::addWindowEventListener(m_renderWindow, this);
	if (!m_oisInputManager){
		OIS::ParamList pl;
		size_t windowHnd = 0;
		std::ostringstream windowHndStr;
		m_renderWindow->getCustomAttribute("WINDOW", &windowHnd);
		windowHndStr << windowHnd;
		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));	// This enables the mouse cursor to be shown
		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
		m_oisInputManager = OIS::InputManager::createInputSystem(pl);
		if (m_oisInputManager->getNumberOfDevices(OIS::OISKeyboard) > 0){
			m_keyboard = static_cast<OIS::Keyboard*>(m_oisInputManager->createInputObject(OIS::OISKeyboard, true));
			m_keyboard->setEventCallback(this);
		}
		if (m_oisInputManager->getNumberOfDevices(OIS::OISMouse) > 0){
			m_mouse = static_cast<OIS::Mouse*>(m_oisInputManager->createInputObject(OIS::OISMouse, true));
			m_mouse->setEventCallback(this);
		}
		if (m_oisInputManager->getNumberOfDevices(OIS::OISJoyStick) > 0){
			m_joysticks.resize(m_oisInputManager->getNumberOfDevices(OIS::OISJoyStick));
			for (unsigned int i = 0; i < m_joysticks.size(); i++){
				OIS::JoyStick* joystick = static_cast<OIS::JoyStick*>(m_oisInputManager->createInputObject(OIS::OISJoyStick, true));
				m_joysticks[i] = new JoyStick(joystick);
			}
		}
		std::fill(m_keys, m_keys + KEYBOARD_KEYS, false);
		std::fill(m_lastKeys, m_lastKeys + KEYBOARD_KEYS, false);
		std::fill(m_mouseButtons, m_mouseButtons + MOUSE_BUTTONS, false);
		std::fill(m_lastMouseButtons, m_lastMouseButtons + MOUSE_BUTTONS, false);
	}
	windowResized(m_renderWindow);
}

void InputSystem::_Shut(){
	if (m_oisInputManager){
		if (m_keyboard){
			m_oisInputManager->destroyInputObject(m_keyboard);
			m_keyboard = nullptr;
		}
		if (m_mouse){
			m_oisInputManager->destroyInputObject(m_mouse);
			m_mouse = nullptr;
		}
		if (m_joysticks.size() > 0){
			for (unsigned int i = 0; i < m_joysticks.size(); i++){
				m_oisInputManager->destroyInputObject(m_joysticks[i]->GetJoyStick());
				delete m_joysticks[i];
				m_joysticks[i] = nullptr;
			}
			m_joysticks.clear();
		}
		OIS::InputManager::destroyInputSystem(m_oisInputManager);
		m_oisInputManager = nullptr;
	}
	Ogre::WindowEventUtilities::removeWindowEventListener(m_renderWindow, this);
}

void InputSystem::_Capture(){
	memcpy(m_lastKeys,m_keys,sizeof(bool)*KEYBOARD_KEYS);
	memcpy(m_lastMouseButtons,m_mouseButtons,sizeof(bool)*MOUSE_BUTTONS);
	m_keyboard->capture();
	m_mouse->capture();
	if (!m_joysticks.empty()){
		for (unsigned int i=0;i<m_joysticks.size();i++){
			m_joysticks[i]->Capture();
		}
	}
}

bool InputSystem::IsKeyDown(int key){
	return m_keys[key];
}

bool InputSystem::IsKeyPressed(int key){
	if (!m_lastKeys[key] && m_keys[key]){
		return true;
	}
	return false;
}

bool InputSystem::IsKeyReleased(int key){
	if (m_lastKeys[key] && !m_keys[key]){
		return true;
	}
	return false;
}

bool InputSystem::IsMouseButtonDown(int btn){
	return m_mouseButtons[btn];
}

bool InputSystem::IsMouseButtonPressed(int btn){
	if (!m_lastMouseButtons[btn] && m_mouseButtons[btn]){
		return true;
	}
	return false;
}

bool InputSystem::IsMouseButtonReleased(int btn){
	if (m_lastMouseButtons[btn] && !m_mouseButtons[btn]){
		return true;
	}
	return false;
}

bool InputSystem::IsJoyStickButtonDown(int btn, int joystickID){
	if (joystickID >= 0 && joystickID < (int)m_joysticks.size()){
		return m_joysticks[joystickID]->IsButtonDown(btn);
	}
	return false;
}

bool InputSystem::IsJoyStickButtonPressed(int btn, int joystickID){
	if (joystickID >= 0 && joystickID < (int)m_joysticks.size()){
		return m_joysticks[joystickID]->IsButtonPressed(btn);
	}
	return false;
}

bool InputSystem::IsJoyStickButtonReleased(int btn, int joystickID){
	if (joystickID >= 0 && joystickID < (int)m_joysticks.size()){
		return m_joysticks[joystickID]->IsButtonReleased(btn);
	}
	return false;
}

bool InputSystem::IsJoyStickPovDown(int pov, int joystickID){
	if ((unsigned int)joystickID >= m_joysticks.size()){
		return false;
	}
	return m_joysticks[joystickID]->IsPovDown(pov);
}

bool InputSystem::IsJoyStickPovPressed(int pov, int joystickID){
	if ((unsigned int)joystickID >= m_joysticks.size()){
		return false;
	}
	return m_joysticks[joystickID]->IsPovPressed(pov);
}

bool InputSystem::IsJoyStickPovReleased(int pov, int joystickID){
	if ((unsigned int)joystickID >= m_joysticks.size()){
		return false;
	}
	return m_joysticks[joystickID]->IsPovReleased(pov);
}


bool InputSystem::IsButtonDown(const Ogre::String& buttonName, int joystickId){
	ButtonList::iterator it = m_buttons.find(buttonName);
	if (it != m_buttons.end()){
		for (unsigned int i = 0; i < it->second.size(); i++){
			switch (it->second[i].first){
			case BTN_TYPE_KEYBOARD:
				return IsKeyDown(it->second[i].second);
				break;
			case BTN_TYPE_MOUSE:
				return IsMouseButtonDown(it->second[i].second);
				break;
			case BTN_TYPE_JOYSTICK:
				return IsJoyStickButtonDown(it->second[i].second, joystickId);
				break;
			default:
				break;
			}
		}
	}
	return false;
}

bool InputSystem::IsButtonPressed(const Ogre::String& buttonName, int joystickId){
	ButtonList::iterator it = m_buttons.find(buttonName);
	if (it != m_buttons.end()){
		for (unsigned int i = 0; i < it->second.size(); i++){
			switch (it->second[i].first){
			case BTN_TYPE_KEYBOARD:
				return IsKeyPressed(it->second[i].second);
				break;
			case BTN_TYPE_MOUSE:
				return IsMouseButtonPressed(it->second[i].second);
				break;
			case BTN_TYPE_JOYSTICK:
				return IsJoyStickButtonPressed(it->second[i].second, joystickId);
				break;
			default:
				break;
			}
		}
	}
	return false;
}

bool InputSystem::IsButtonReleased(const Ogre::String& buttonName, int joystickId){
	ButtonList::iterator it = m_buttons.find(buttonName);
	if (it != m_buttons.end()){
		for (unsigned int i = 0; i < it->second.size(); i++){
			switch (it->second[i].first){
			case BTN_TYPE_KEYBOARD:
				return IsKeyReleased(it->second[i].second);
				break;
			case BTN_TYPE_MOUSE:
				return IsMouseButtonReleased(it->second[i].second);
				break;
			case BTN_TYPE_JOYSTICK:
				return IsJoyStickButtonReleased(it->second[i].second, joystickId);
				break;
			default:
				break;
			}
		}
	}
	return false;
}

void InputSystem::AddButton(const Ogre::String& name, int type, int id){
	m_buttons[name].push_back(std::make_pair(type, id));
}

void InputSystem::RemoveButton(const Ogre::String& name){
	ButtonList::iterator it = m_buttons.find(name);
	if (it != m_buttons.end()){
		m_buttons.erase(it);
	}
}

float InputSystem::GetJoystickAxis(int axis, int joystickID){
	if ((unsigned int)joystickID >= m_joysticks.size()){
		return 0.0f;
	}
	return m_joysticks[joystickID]->GetAxis(axis);
}

int InputSystem::GetJoystickPov(int joystickID){
	if ((unsigned int)joystickID >= m_joysticks.size()){
		return -1;
	}
	return m_joysticks[joystickID]->GetPov();
}

void InputSystem::RemoveButton(const Ogre::String& name, int type, int id){
	ButtonList::iterator it = m_buttons.find(name);
	if (it != m_buttons.end()){
		for (unsigned int i = 0; i < it->second.size(); i++){
			if (it->second[i].first == type && it->second[i].second == id){
				it->second.erase(it->second.begin() + i);
				return;
			}
		}
	}
}

bool InputSystem::keyPressed(const OIS::KeyEvent& e){
	m_keys[e.key] = true;
	return true;
}

bool InputSystem::keyReleased(const OIS::KeyEvent& e){
	m_keys[e.key] = false;
	return true;
}

bool InputSystem::mouseMoved(const OIS::MouseEvent& e){
	return true;
}

bool InputSystem::mousePressed(const OIS::MouseEvent& e, OIS::MouseButtonID id){
	m_mouseButtons[id] = true;
	return true;
}

bool InputSystem::mouseReleased(const OIS::MouseEvent& e, OIS::MouseButtonID id){
	m_mouseButtons[id] = false;
	return true;
}

void InputSystem::windowResized(Ogre::RenderWindow* rw){
	const OIS::MouseState& mouseState = m_mouse->getMouseState();
	mouseState.width = (int)rw->getWidth();
	mouseState.height = (int)rw->getHeight();
}

void InputSystem::windowClosed(Ogre::RenderWindow* rw){

}

}